#ifndef __MY_DATABASE_H__
#define __MY_DATABASE_H__
#include "Log.hpp"
#include "MySqlClient.hpp"
#include <jsoncpp/json/json.h>
#include <cassert>

using namespace LogModule;

class Table_User
{
private:
    template <class... ARGS>
    std::string MakeSql(const std::string format, ARGS... args)
    {
        char sql[4096];
        // printf(format.c_str(), args...);
        sprintf(sql, format.c_str(), args...);
        return sql;
    }

public:
    Table_User(const std::string &host, const std::string &user, const std::string &passwd, const std::string &db)
        : _mysql(host, user, passwd, db)
    {
        assert(Util_Hash::Init());
    }

    // 将用户信息注册到用户表
    bool Register(const std::string &name, const std::string &passwd)
    {
        if (name.empty() || passwd.empty())
        {
            LOG(LogLevel::ERROR) << "Table_User::Register: 用户名或密码为空!";
            return false;
        }

        Json::Value tmp;
        if (SelectByName(name, tmp))
        {
            LOG(LogLevel::ERROR) << "Table_User::Register: 用户[" << name.c_str() << "]已存在!";
            return false;
        }

        static const std::string insert_info = "INSERT INTO user (name, passwd, points, total_count, win_count) "
                                               "VALUES ('%s', '%s', 1200, 0, 0);";
        std::string sql = MakeSql(insert_info.c_str(), name.c_str(), Util_Hash::Password(passwd).c_str());
        auto ret = _mysql.Query(sql);
        return ret.first != 0;
    }

    // 验证用户登录信息
    bool LoginCheck(Json::Value &login_info)
    {
        std::string name = login_info["name"].asString();
        std::string passwd = login_info["passwd"].asString();
        if (name.empty() || passwd.empty())
        {
            LOG(LogLevel::ERROR) << "Table_User::LoginCheck: 用户名或密码为空!";
            return false;
        }

        if (!SelectByName(name, login_info))
        {
            return false;
        }

        return Util_Hash::Verify(passwd, login_info["passwd"].asString());
    }

    // 根据用户名查找用户信息
    bool SelectById(const id_t id, Json::Value &user)
    {
        static const std::string select_by_id = "SELECT id, name, passwd, points, total_count, win_count FROM user WHERE id=%u;";
        std::string sql = MakeSql(select_by_id, id);
        auto ret = _mysql.Query(sql);
        if (ret.first == 0)
        {
            LOG(LogLevel::ERROR) << "Table_User::SelectById: 用户id[%u]不存在!", id;
            return false;
        }

        MYSQL_ROW row = ret.second->NextRow();
        user["id"] = std::stoi(row[0]);
        user["name"] = row[1];
        user["passwd"] = row[2];
        user["points"] = std::stoi(row[3]);
        user["total_count"] = std::stoi(row[4]);
        user["win_count"] = std::stoi(row[5]);
        return true;
    }

    // 根据用户id查找用户信息
    bool SelectByName(const std::string &name, Json::Value &user)
    {
        static const std::string select_by_name = "SELECT id, name, passwd, points, total_count, win_count FROM user WHERE name='%s';";
        std::string sql = MakeSql(select_by_name, name.c_str());
        auto ret = _mysql.Query(sql);
        if (ret.first == 0)
        {
            // LOG(LogLevel::ERROR) << "Table_User::SelectByName: 用户[%s]不存在!", name.c_str();
            return false;
        }

        MYSQL_ROW row = ret.second->NextRow();
        user["id"] = std::stoi(row[0]);
        user["name"] = row[1];
        user["passwd"] = row[2];
        user["points"] = std::stoi(row[3]);
        user["total_count"] = std::stoi(row[4]);
        user["win_count"] = std::stoi(row[5]);
        return true;
    }

    // 计数胜利: 总场次++ 胜利场次++ 积分+30
    bool CountWin(const id_t id)
    {
        static const std::string update_win = "UPDATE user SET total_count=total_count+1, win_count=win_count+1, points=points+30 WHERE id=%u;";
        std::string sql = MakeSql(update_win, id);
        auto ret = _mysql.Query(sql);
        if (ret.first == 0)
        {
            LOG(LogLevel::ERROR) << "Table_User::CountWin: 用户id[%u]数据更新失败!", id;
            return false;
        }
        return true;
    }

    // 计数失败
    bool CountLose(const id_t id)
    {
        static const std::string update_win = "UPDATE user SET total_count=total_count+1, points=points-30 WHERE id=%u;";
        std::string sql = MakeSql(update_win, id);
        auto ret = _mysql.Query(sql);
        if (ret.first == 0)
        {
            LOG(LogLevel::ERROR) << "Table_User::CountWin: 用户id[%u]数据更新失败!", id;
            return false;
        }
        return true;
    }

    ~Table_User()
    {
    }

private:
    MySqlClient _mysql;
};

#endif